package com.ytd.common.net;

import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.ytd.common.base.BaseApplication;
import com.ytd.common.bean.BaseRequest;
import com.ytd.common.bean.BaseResponse;
import com.ytd.common.bean.ResultInfo;
import com.ytd.common.bean.request.BaseRequestData;
import com.ytd.common.constant.ApiConstants;
import com.ytd.common.util.AESUtils;
import com.ytd.common.util.GsonUtil;
import com.ytd.common.util.LogUtil;
import com.ytd.common.util.RSAUtils;
import com.ytd.common.util.YtdConfig;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class YtdSocket {
    private static final String TAG = "Socket";
    private static final int GET_CURRENT_TIME_COUNT = 60;
    private static final String OFFLINE_STRING = "{\"code\":\"offline\"}";
    private BaseResponse offlineResponse;

    private static final String EOF_FLAG = "\r\n";
    Socket mSocket = null;
    BufferedReader mBufferedReader = null;//接收数据
    OutputStream outputStream = null;//发送数据
    private Timer heartTimer = new Timer();
    private Timer reconnectTimer = new Timer();
    private TimerTask heartTask;
    private TimerTask reconnectTask;
    public boolean isConnect = false;

    private boolean isReconnectStart;
    private int reconnectCount;
    private int nowReconnectCount;
    private boolean isClose = false;

    SocketCallback socketcallback;

    ExecutorService pool = Executors.newSingleThreadExecutor();

    public YtdSocket(SocketCallback callback) {
        socketcallback = callback;
        initSocket();
    }

    //初始化socket连接
    private void initSocket() {
        isReleaseSocket = false;
        if (isClose) {
            return;
        }
        if (mSocket == null && !isConnect) {
            isConnect = true;
            new ReadThread().start();
        }
    }

    private class ReadThread extends Thread {

        @Override
        public void run() {
            try {
                LogUtil.d("SocketRead线程开始：");
                mSocket = new Socket();
                SocketAddress socAddress = new InetSocketAddress(YtdConfig.getIP(), YtdConfig.getPort());
                LogUtil.d("connect:" + YtdConfig.getIP() + ":" + YtdConfig.getPort());
                if (mSocket == null) {
                    mSocket = new Socket();
                }
                mSocket.connect(socAddress, 5000);
                mSocket.setKeepAlive(true);
                mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
                outputStream = mSocket.getOutputStream();
                LogUtil.d("connect success: socketcallback.init()");
                socketcallback.init();
                heartStart();
                String readvalue;
                while (isConnect) {
                    readvalue = mBufferedReader.readLine();
                    if (readvalue != null) {
                        if (YtdConfig.isDeviceActivate()) {
                            ResultInfo res = GsonUtil.fromJson(readvalue, ResultInfo.class);
                            if (res != null && !TextUtils.isEmpty(res.getKey())) {
                                String aes = RSAUtils.decryptByPrivateKey(Base64.decode(res.getKey(), Base64.DEFAULT),
                                        Base64.decode(YtdConfig.getRsaPrivateKey(), Base64.DEFAULT));
                                readvalue = AESUtils.decrypt128(res.getBody(), aes);
                            }
                        }
                        if (!TextUtils.isEmpty(readvalue) && !TextUtils.isEmpty(mHeartBeatId) &&
                                readvalue.contains(mHeartBeatId)) {
                            //LogUtil.e("response:心跳正常");
                        } else {
                            LogUtil.e("response:" + readvalue);
                        }
                        BaseResponse baseResponse = GsonUtil.fromJson(readvalue, BaseResponse.class);
                        socketcallback.onReadData(baseResponse);
                        endReconnect();
                    }
                }
                LogUtil.e("SocketRead线程停止");
            } catch (Exception e) {
                isConnect = false;
                LogUtil.e("SocketRead线程异常--" + e.getMessage());
                nowReconnectCount++;
                startReconnect();
            }
        }

    }

    public void sendOffline() {
        if (offlineResponse == null) {
            offlineResponse = GsonUtil.fromJson(OFFLINE_STRING, BaseResponse.class);
        }
        socketcallback.onReadData(offlineResponse);
    }

    private void startReconnect() {
        if (isReconnectStart || isClose) {
            if (isReconnectStart && nowReconnectCount < 3) {
                SystemClock.sleep(5000);
                LogUtil.e("SocketRead线程异常--防网络波动--直接开始重连:" + nowReconnectCount);
                LogUtil.e("releaseSocket nowReconnectCount");
                releaseSocket(true);
            }
            return;
        }
        if (reconnectTimer == null) {
            reconnectTimer = new Timer();
        }
        if (reconnectTask == null) {
            reconnectTask = new TimerTask() {
                @Override
                public void run() {
                    reconnectCount++;
                    if (reconnectCount == 3) {
                        reconnectCount = 0;
                        sendOffline();
                    }
                    LogUtil.e("releaseSocket reconnectTask");
                    releaseSocket(true);
                    if (BaseApplication.getInstance().isNetworkAvailable()) {
                        LogUtil.e("SocketRead线程异常--开始重连");
                    } else {
                        LogUtil.e("SocketRead线程异常--开始重连---无网络");
                    }
                    if (isClose) {
                        endReconnect();
                    }
                }
            };
        }
        LogUtil.d(TAG, "重连开始");
        reconnectTimer.schedule(reconnectTask, 0, YtdConfig.getReconnectTime() * 1000L);
        isReconnectStart = true;
        reconnectCount = 0;
        LogUtil.e("SocketRead线程异常--防网络波动--直接开始重连:" + nowReconnectCount);
    }

    private void endReconnect() {
        isReconnectStart = false;
        reconnectCount = 0;
        nowReconnectCount = 0;
        if (reconnectTask != null) {
            reconnectTask.cancel();
            reconnectTask = null;
        }
        if (reconnectTimer != null) {
            reconnectTimer.purge();
            reconnectTimer.cancel();
            reconnectTimer = null;
        }
    }

    public boolean sendMsg(final String msg) {
        String sss = msg + EOF_FLAG;
        pool.execute(() -> {
            try {
                LogUtil.d(TAG, "send:write: " + msg);
                outputStream.write(sss.getBytes());
                outputStream.flush();
            } catch (Exception e) {
                LogUtil.e("Socket发送异常--" + e.getMessage());
                /*重连*/
                LogUtil.e("releaseSocket sendMsg");
                releaseSocket(true);
            }
        });
        return true;
    }

    private String mHeartBeatId = "";
    private int mHeartBeatCount = 0;
    private int mErrorHeartBeatCount = 0;

    private void heartStart() {
        if (heartTimer == null) {
            heartTimer = new Timer();
        }
        if (heartTask == null) {
            heartTask = new TimerTask() {

                @Override
                public void run() {
                    try {
                        if (YtdConfig.isDeviceActivate()) {
                            heartBeat();
                        }
                    } catch (Exception e) {
                        /*发送失败说明socket断开了或者出现了其他错误*/
                        LogUtil.e("心跳发送失败.开始重连--" + e.getMessage() + "---" + Log.getStackTraceString(e));
                        /*重连*/
                        LogUtil.e("releaseSocket heartBeat");
                        releaseSocket(true);
                    }
                }
            };
        }
        LogUtil.d("心跳开始");
        heartTimer.schedule(heartTask, 0, YtdConfig.getHeartBeatTime() * 1000L);
    }

    public void resetHeartTimer() {
        if (heartTask != null) {
            heartTask.cancel();
            heartTask = null;
        }
        if (heartTimer != null) {
            heartTimer.purge();
            heartTimer.cancel();
            heartTimer = null;
        }
        heartStart();
    }

    BaseRequestData heartBeatData = new BaseRequestData();
    BaseRequest heartBeatRequest = new BaseRequest();

    public void heartBeat() {
        mHeartBeatId = UUID.randomUUID().toString();
        heartBeatRequest.requestId = mHeartBeatId;
        heartBeatRequest.interfaceName = ApiConstants.HEART_BEAT;
        heartBeatRequest.data = heartBeatData;
        heartBeatRequest.timeout = 5000L;
        RequestManager.getInstance().request(heartBeatRequest, new NetCallBack<Object>() {
            @Override
            public void onSuccess(Object result) {
                mErrorHeartBeatCount = 0;
            }

            @Override
            public void onFail(int code, String msg) {
                LogUtil.d("心跳失败：" + code + "---" + msg);
                mErrorHeartBeatCount++;
                if (mErrorHeartBeatCount == 3) {
                    sendOffline();
                    LogUtil.e("releaseSocket heartBeat mErrorHeartBeatCount");
                    releaseSocket(true);
                }
            }
        });
        mHeartBeatCount++;
        if (mHeartBeatCount == GET_CURRENT_TIME_COUNT) {
            mHeartBeatCount = 0;
            RequestManager.getInstance().getCurrentTime();
        }
    }

    private boolean isReleaseSocket;

    /*socket重连*/
    public synchronized void releaseSocket(boolean isReConnect) {
        if (isReleaseSocket) {
            LogUtil.e("releaseSocket isReleaseSocket return;");
            return;
        }
        if (mSocket == null) {
            LogUtil.e("releaseSocket mSocket == null return;");
            return;
        }
        if (heartTask != null) {
            heartTask.cancel();
            heartTask = null;
            LogUtil.e("releaseSocket heartTask = null");
        }
        if (heartTimer != null) {
            try {
                heartTimer.purge();
                heartTimer.cancel();
                heartTimer = null;
            } catch (Throwable exception) {
                LogUtil.d("releaseSocket:heartTimer.cancel()" + exception.getMessage());
            }
            LogUtil.e("releaseSocket heartTimer = null");
        }
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            outputStream = null;
            LogUtil.e("releaseSocket outputStream = null");
        }
        if (mBufferedReader != null) {
            try {
                mBufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mBufferedReader = null;
            LogUtil.e("releaseSocket mBufferedReader = null");
        }
        if (mSocket != null) {
            try {
                mSocket.close();
            } catch (IOException e) {
            }
            mSocket = null;
            LogUtil.e("releaseSocket mSocket = null");
        }
        RequestManager.release();
        /*重新初始化socket*/
        if (isReConnect) {
            LogUtil.e("releaseSocket isReConnect");
            isReleaseSocket = true;
            SystemClock.sleep(200);//避免多线程问题导致mSocket = null
            initSocket();
            LogUtil.e("releaseSocket end");
        }
    }

    public void close() {
        isClose = true;
        releaseSocket(false);
        endReconnect();
    }
}
